# _*_ coding utf-8 _*_
# FILENAME：.py
# DESCRIPTION: 
# AUTH: 
# DATE: 2022/6/82:45 下午
import datetime
import logging
import threading
import time
import traceback

from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtWidgets import *

from algorithm.partsRequire import CommentsUtils
from components.BaseMainWindow import BaseMainWindow
from components.MessageBoxComponent import MessageBox
from constant import CalculateType, CacheType
from models.asyncExecLogModel import AsyncCalculateLogModel
from models.baseModel import get_session
from models.requireModel import RequireModel, RequireDetailsModel
from utils.cacheUtils import CacheThread
from utils.confUtils import read_performance_config
from views.require.selectBom import SelectBom
from views.require.selectDelayTime import SelectDelayTime
from views.require.selectParts import SelectParts

from views.require.selectProduceQueue import SelectProduceQueue
from views.require.selectProduceSpeed import SelectProduceSpeed


class CalculateForm(BaseMainWindow):
    __id = None
    __bomId = None
    __produceQueueId = None
    __produceSpeedId = None
    __partsId = None
    __delayTimeId = None
    __parent = None

    __factoryName = None
    __productionLineName = None

    def __init__(self, parentWidget, id, factory_name, production_line_name):
        super(CalculateForm, self).__init__()
        self.__parent = parentWidget
        self.__id = id
        self.__factoryName = factory_name
        self.__productionLineName = production_line_name
        self.setupUi(self)

    def setupUi(self, MainWindow):
        MainWindow.setObjectName("MainWindow")
        MainWindow.resize(550, 400)
        MainWindow.setWindowTitle("零件需求运算")
        self.centralwidget = QtWidgets.QWidget(MainWindow)
        self.centralwidget.setObjectName("centralwidget")

        '''水平布局'''
        hbox = QHBoxLayout()
        self.save_btn = QPushButton()
        self.save_btn.setText('运算')
        self.save_btn.setFixedWidth(80)
        self.save_btn.clicked.connect(self.save_btn_click)

        self.cancel_btn = QPushButton()
        self.cancel_btn.setText('关闭')
        self.cancel_btn.setFixedWidth(80)
        self.cancel_btn.clicked.connect(self.cancel_btn_click)
        hbox.addStretch(1)  # 占位
        hbox.addWidget(self.save_btn)
        hbox.addWidget(self.cancel_btn)
        hbox.addStretch(1)  # 占位
        btnPanelWidget = QWidget()
        btnPanelWidget.setLayout(hbox)

        '''表单布局'''
        self.fac_lab = QLabel()
        self.fac_lab.setText('工厂：')
        self.fac_lab1 = QLabel()
        self.fac_lab1.setText(self.__factoryName)
        self.fac_lab1.setFixedHeight(20)

        self.production_lab = QLabel()
        self.production_lab.setText('生产线：')
        self.production_lab1 = QLabel()
        self.production_lab1.setText(self.__productionLineName)
        self.production_lab1.setFixedHeight(20)

        self.bom_lab = QLabel()
        self.bom_lab.setText('BOM：')
        self.bom_edit = QLineEdit()
        self.bom_btn = QPushButton("选择")
        self.bom_btn.clicked.connect(self.openSelectBom)

        self.production_queue_lab = QLabel()
        self.production_queue_lab.setText('生产队列：')
        self.production_queue_edit = QLineEdit()
        self.production_queue_btn = QPushButton("选择")
        self.production_queue_btn.clicked.connect(self.openSelectProduceQueue)

        self.production_speed_lab = QLabel()
        self.production_speed_lab.setText('生产速度：')
        self.production_speed_edit = QLineEdit()
        self.production_speed_btn = QPushButton("选择")
        self.production_speed_btn.clicked.connect(self.openSelectProduceSpeed)

        self.parts_lab = QLabel()
        self.parts_lab.setText('零件信息：')
        self.parts_edit = QLineEdit()
        self.parts_btn = QPushButton("选择")
        self.parts_btn.clicked.connect(self.openSelectParts)

        self.load_delay_time_lab = QLabel()
        self.load_delay_time_lab.setText('装配延误时间：')
        self.delay_time_edit = QLineEdit()
        self.delay_time_btn = QPushButton("选择")
        self.delay_time_btn.clicked.connect(self.openSelectDelayTime)

        #  布局
        gbox = QGridLayout()
        gbox.addWidget(self.fac_lab, 0, 0, 1, 1)
        gbox.addWidget(self.fac_lab1, 0, 1, 1, 1)

        gbox.addWidget(self.production_lab, 1, 0, 1, 1)
        gbox.addWidget(self.production_lab1, 1, 1, 1, 1)

        gbox.addWidget(self.bom_lab, 2, 0, 1, 1)
        gbox.addWidget(self.bom_edit, 2, 1, 1, 1)
        gbox.addWidget(self.bom_btn, 2, 2, 1, 1)

        gbox.addWidget(self.production_queue_lab, 3, 0, 1, 1)
        gbox.addWidget(self.production_queue_edit, 3, 1, 1, 1)
        gbox.addWidget(self.production_queue_btn, 3, 2, 1, 1)

        gbox.addWidget(self.production_speed_lab, 4, 0, 1, 1)
        gbox.addWidget(self.production_speed_edit, 4, 1, 1, 1)
        gbox.addWidget(self.production_speed_btn, 4, 2, 1, 1)

        gbox.addWidget(self.parts_lab, 5, 0, 1, 1)
        gbox.addWidget(self.parts_edit, 5, 1, 1, 1)
        gbox.addWidget(self.parts_btn, 5, 2, 1, 1)

        gbox.addWidget(self.load_delay_time_lab, 6, 0, 1, 1)
        gbox.addWidget(self.delay_time_edit, 6, 1, 1, 1)
        gbox.addWidget(self.delay_time_btn, 6, 2, 1, 1)

        # gbox.setColumnStretch(3, 1)

        gbox.addWidget(btnPanelWidget, 7, 0, 1, 3)

        vbox = QVBoxLayout()
        vbox.addLayout(gbox)
        vbox.addLayout(hbox)

        self.centralwidget.setLayout(vbox)

        MainWindow.setCentralWidget(self.centralwidget)
        self.menubar = QtWidgets.QMenuBar(MainWindow)
        self.menubar.setGeometry(QtCore.QRect(0, 0, 550, 26))
        self.menubar.setObjectName("menubar")
        MainWindow.setMenuBar(self.menubar)
        self.statusbar = QtWidgets.QStatusBar(MainWindow)
        self.statusbar.setObjectName("statusbar")
        MainWindow.setStatusBar(self.statusbar)

        # self.retranslateUi(MainWindow)
        # QtCore.QMetaObject.connectSlotsByName(MainWindow)

    # def retranslateUi(self, MainWindow):
    #     _translate = QtCore.QCoreApplication.translate
    #     MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow1"))

    # 保存
    def save_btn_click(self):
        if self.bom_edit.text().strip() == '':
            messageBox = MessageBox()
            messageBox.warrning(title="提醒", msg="bom信息不能为空")
            return

        if self.production_queue_edit.text().strip() == '':
            messageBox = MessageBox()
            messageBox.warrning(title="提醒", msg="生产队列不能为空")
            return

        if self.production_speed_edit.text().strip() == '':
            messageBox = MessageBox()
            messageBox.warrning(title="提醒", msg="生产速度不能为空")
            return

        if self.parts_edit.text().strip() == '':
            messageBox = MessageBox()
            messageBox.warrning(title="提醒", msg="零件信息不能为空")
            return

        if self.delay_time_edit.text().strip() == '':
            messageBox = MessageBox()
            messageBox.warrning(title="提醒", msg="装配延误时间不能为空")
            return
        #
        time = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
        session = get_session()
        if self.__id > 0:
            # 编辑
            params = {
                'bom_version_id': self.__bomId,
                'produce_queue_version_id': self.__produceQueueId,
                'produce_speed_version_id': self.__produceSpeedId,
                'parts_version_id': self.__partsId,
                'load_delay_time_version_id': self.__delayTimeId,
                'update_date': time,
                'status': 1
            }
            # 更新
            session.query(RequireModel).filter(RequireModel.id == self.__id).update(params)
            # 提交&关闭
            session.commit()
            session.close()

            # 异步计算
            cal_thread = CalThread(self.__id)
            cal_thread.start()

            # 刷新列表
            self.__parent.query_click()

        #
        self.close()

    # 关闭
    def cancel_btn_click(self):
        self.close()

    def openSelectProduceQueue(self):
        self.selectProduceQueue = SelectProduceQueue(self)
        self.selectProduceQueue.show()

    def openSelectProduceSpeed(self):
        self.selectProduceSpeed = SelectProduceSpeed(self)
        self.selectProduceSpeed.show()

    def openSelectBom(self):
        self.selectBom = SelectBom(self)
        self.selectBom.show()

    def openSelectParts(self):
        self.selectParts = SelectParts(self)
        self.selectParts.show()

    def openSelectDelayTime(self):
        self.selectDelayTime = SelectDelayTime(self)
        self.selectDelayTime.show()

    def setProduceQueueId(self, id):
        self.__produceQueueId = id

    def setProduceSpeedId(self, id):
        self.__produceSpeedId = id

    def setBomId(self, id):
        self.__bomId = id

    def setPartsId(self, id):
        self.__partsId = id

    def setDelayTimeId(self, id):
        self.__delayTimeId = id


"""
计算零件需求
"""


class CalThread(threading.Thread):
    def __init__(self, require_id):
        super(CalThread, self).__init__()  # 重构run函数必须写
        self.require_id = require_id

    def run(self):
        session = get_session()
        # 更新运算状态
        session.query(RequireModel).filter(RequireModel.id == self.require_id).update({'status': 2})
        # 写日志表
        log = AsyncCalculateLogModel()
        log.type = CalculateType.REQUIRE.value
        log.version_id = self.require_id
        log.status = 0
        log.start_time = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
        session.add(log)
        # 提交&关闭
        session.commit()
        log_id = log.id
        session.close()

        try:
            # 运算
            require_details = []
            require_algorithm = CommentsUtils()
            cal_require_details, init_time, cal_time = require_algorithm.get_welding_assembly(self.require_id)

            session = get_session()
            # 分批保存数量
            bulk_save_count = read_performance_config('bulk_save_count')
            # 删除上次运算
            session.query(RequireDetailsModel).filter(RequireDetailsModel.require_id == self.require_id).delete()
            # 保存数据
            save_start_time = int(time.time())
            for data in cal_require_details:
                require_detail = RequireDetailsModel()
                require_detail.require_id = self.require_id
                require_detail.parts_code = data['零件件号']
                require_detail.parts_name = data['零件名称']
                require_detail.arrival_time = data['到货时间']
                require_detail.quantity = data['数量']
                require_detail.supplier_name = data['供应商名称']

                require_details.append(require_detail)

                # 分批保存
                if 0 < int(bulk_save_count) <= len(require_details):
                    # 保存
                    session.bulk_save_objects(require_details)
                    require_details = []

            # 保存
            session.bulk_save_objects(require_details)
            session.commit()
        except Exception as e:
            # 回滚
            session.rollback()
            # 更新运算状态
            session.query(RequireModel).filter(RequireModel.id == self.require_id).update({'status': 4})
            # 更新日志
            session.query(AsyncCalculateLogModel).filter(AsyncCalculateLogModel.id == log_id).update({
                'status': 2,
                'end_time': datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
                'reason': e
            })
            session.commit()

            # 记录日志
            logging.error(traceback.format_exc())
        else:
            # 更新运算状态
            session.query(RequireModel).filter(RequireModel.id == self.require_id).update({'status': 3})
            # 更新日志
            session.query(AsyncCalculateLogModel).filter(AsyncCalculateLogModel.id == log_id).update({
                'status': 1,
                'end_time': datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
                'init_time': init_time,
                'cal_time': cal_time,
                'save_time': int(time.time()) - save_start_time
            })
            # 提交&关闭
            session.commit()

            # 缓存数据
            cache_thread = CacheThread(CacheType.REQUIRE.value, self.require_id)
            cache_thread.start()
        finally:
            session.close()
